<template>
	<div class="tl-upload-container">
		<slot>
			<el-button icon="el-icon-paperclip" type="primary" :disabled="disabled" @click="openUploadDialog()" v-if="isDisplayDefaultElement">{{ btnTitle }}[{{ fileList.length > 0 ? fileList.length : fileCount }}]</el-button>
		</slot>
		<el-dialog v-if="!(previewMode && !editable)" :visible.sync="visible" :title="title" :close-on-click-modal="false" v-dialogDrag class="tl-dialog" @open="open" @close="close" width="1200px" :append-to-body="true" :modal-append-to-body="true">
			<el-row>
				<el-col :span="16">
					<el-upload class="tl-upload" v-if="editable" :show-file-list="false" :action="baseUrl + url.upload" :headers="header" :file-list="uploadFileList" :data="postData" multiple :on-success="uploadSuccess" :before-upload="beforeUpload" :on-error="uploadFail" :on-progress="progress">
						<el-button slot="default" icon="el-icon-upload" type="primary" plain :disabled="!editable" style="display:block">添加文件</el-button>
						<div class="upload-queue">
							<el-tooltip class="item" :key="file.uid" v-for="file in uploadingFileList" effect="dark" :content="file.name" placement="top">
								<el-progress :text-inside="true" :stroke-width="20" :percentage="parseInt(file.percentage)" :format="formatProcess"></el-progress>
							</el-tooltip>
						</div>
						<div slot="tip" class="el-upload__tip">
							<span v-if="limitType"> 请上传{{ limitType }}文件&nbsp;&nbsp;</span>
							<span v-if="limitSize">单个附件不超过{{ limitSize / 1024 }}MB&nbsp;&nbsp;</span>
							<span v-if="extendDesc">{{ extendDesc }}&nbsp;&nbsp;</span>
						</div>
					</el-upload>
					<span v-else>&nbsp;</span>
				</el-col>
				<el-col :span="8" style="text-align:right;padding-bottom:5px;">
					<el-radio-group v-model="listType" style="float:right" class="exchange-tab">
						<el-radio-button label="table"><i class="el-icon-date"/></el-radio-button>
						<el-radio-button label="thumb"><i class="el-icon-picture-outline"/></el-radio-button>
						<el-radio-button label="list"><i class="el-icon-s-operation"/></el-radio-button>
					</el-radio-group>
					<el-button icon="el-icon-data-board" type="primary" @click="previewVisible = true" style="float:right;margin-right:5px;">预览模式</el-button>
				</el-col>
			</el-row>
			<div class="tl-upload">
				<ul class="el-upload-list el-upload-list--picture-card" v-if="listType === 'thumb'">
					<li :tabindex="index" class="el-upload-list__item is-success" v-for="(file, index) in fileList" :key="file.id">
						<div>
							<el-avatar shape="square" :size="136" fit="fit" :src="file.ex_base64 ? file.ex_base64 : file.ex_typeUrl"></el-avatar>
							<p class="name">{{ file.displayname }}</p>
							<span class="el-upload-list__item-actions">
								<span class="el-upload-list__item-preview" v-if="file.ex_type === 'image' || file.ex_type === 'pdf'"><i class="el-icon-zoom-in" @click.stop="handleView(file)"></i></span>
								<span v-if="editable" class="el-upload-list__item-delete" @click.stop="handleDownload(file)"><i class="el-icon-download"></i></span>
								<span v-if="editable" class="el-upload-list__item-delete" @click.stop="handleRemove(file)"><i class="el-icon-delete"></i></span>
							</span>
						</div>
					</li>
				</ul>
				<ul class="el-upload-list el-upload-list--text" v-if="listType === 'list'">
					<li :tabindex="index" class="el-upload-list__item is-success" v-for="(file, index) in fileList" :key="file.id">
						<a class="el-upload-list__item-name"><i class="el-icon-document"></i>{{ file.displayname }}</a>
						<label class="el-upload-list__item-status-label">
							<i class="el-icon-zoom-in" v-if="file.ex_type === 'image' || file.ex_type === 'pdf'" @click.stop="handleView(file)"></i>
							<i v-if="editable" class="el-icon-download" @click.stop="handleDownload(file)"></i>
							<i v-if="editable" class="el-icon-delete" @click.stop="handleRemove(file)"></i>
						</label>
					</li>
				</ul>
				<el-table v-if="listType === 'table'" ref="mainTable" class="tl-table" height="300px" :data="fileList" style="width: 100%;" row-key="id" border fit :default-sort="{ prop: 'id', order: 'ascending' }">
					<el-table-column type="index" label="序号" width="55px" align="center"> </el-table-column>
					<el-table-column prop="displayname" label="文件名称"></el-table-column>
					<el-table-column prop="filetype" label="文件类型" width="120px" align="center"></el-table-column>
					<el-table-column prop="filesize" label="文件大小" width="120px" align="center"></el-table-column>
					<el-table-column prop="createon" label="上传时间" width="180px" :formatter="dateFormat"></el-table-column>
					<el-table-column label="操作" width="210px" header-align="center" align="center" v-slot="slotProps" fixed="right">
						<el-button type="text" :disabled="disablePreview(slotProps.row.ex_type)" icon="el-icon-view" @click="handleView(slotProps.row)">查看</el-button>
						<el-button type="text" icon="el-icon-download" @click="handleDownload(slotProps.row)">下载</el-button>
						<el-button type="text" icon="el-icon-delete" @click="handleRemove(slotProps.row)" :disabled="!editable">删除</el-button>
					</el-table-column>
				</el-table>
				<div :id="viewerId"></div>
				<el-dialog :visible.sync="pdfVisible" :title="pdfTitle" v-dialogDrag class="tl-dialog" width="90%" :append-to-body="true">
					<iframe v-show="pdfFile" :src="pdfFile" width="100%" height="600px"></iframe>
					<div slot="footer" class="dialog-footer" style="text-align:right;">
						<el-button type="primary" @click="pdfVisible = false">关闭</el-button>
					</div>
				</el-dialog>
			</div>
		</el-dialog>
		<el-dialog :visible.sync="previewVisible" :title="previewTitle" :close-on-click-modal="false" top="10px" width="96%" v-dialogDrag class="tl-dialog" @open="previewOpen" @close="previewClose" :append-to-body="true" :modal-append-to-body="true">
			<tl-preview ref="preview" :sourceType="sourceType" :sourceId="sourceId" :extendData="extendData" :outFileList="fileList"></tl-preview>
			<div slot="footer" class="dialog-footer" style="text-align:right;">
				<el-button type="primary" @click="previewVisible = false">关闭</el-button>
			</div>
		</el-dialog>
	</div>
</template>

<script>
import axios from '@tapui/utils/request'
import word from '@tapui/imgs/file/word.png'
import excel from '@tapui/imgs/file/excel.png'
import pdf from '@tapui/imgs/file/pdf.png'
import zip from '@tapui/imgs/file/zip.png'
import image from '@tapui/imgs/file/image.png'
import txt from '@tapui/imgs/file/txt.png'
import ppt from '@tapui/imgs/file/ppt.png'
import video from '@tapui/imgs/file/video.png'
import other from '@tapui/imgs/file/other.png'
import { getAction, deleteAction, putAction } from '@tapui/utils/http'
import Viewer from 'viewerjs'
import 'viewerjs/dist/viewer.min.css'
import tlPreview from '@/components/preview'
export default {
	name: 'TlAttachment',
	components: { tlPreview },
	data() {
		return {
			fileList: [],
			uploadFileList: [],
			fileCount: 0,
			waitCount: 0,
			previewTitle: '附件预览',
			previewVisible: false,
			postData: {
				sourceType: this.sourceType,
				sourceId: this.sourceId
			},
			baseUrl: axios.defaults.baseURL,
			header: {
				Authorization: 'Bearer ' + this.$store.getters.token
			},
			imageViewer: null,
			totalPage: 0,
			visible: false,
			pdfVisible: false,
			pdfTitle: 'pdf文件',
			pdfFile: null,
			url: {
				upload: '/cbo/attachment/upload',
				download: '/cbo/attachment/download',
				display: '/cbo/attachment/display',
				query: '/cbo/attachment/queryAttachmentList',
				delete: '/cbo/attachment/delete',
				queryCount: '/cbo/attachment/calculateCount',
				viewWord: '/qms/qemProblemAlert/previewDownLoad'
			},
			fileTypeIcon: {
				';pdf;': pdf,
				';doc;docx;': word,
				';xls;xlsx;': excel,
				';zip;rar;7z;': zip,
				';jpg;gif;png;bmp;': image,
				';txt;log;': txt,
				';ppt;pptx;': ppt,
				';mp3;mp4;mkv;rmvb': video
			},
			listType: 'table',
			viewerId: 'viewer'
		}
	},
	props: {
		sourceType: {
			type: String,
			required: true
		},
		defaultListType: {
			type: String,
			default: 'table'
		},
		sourceId: {
			type: Number,
			default: 0
		},
		limitCount: {
			type: Number,
			default: 999999
		},
		limitType: {
			type: String,
			default: ''
		},
		// 文件黑名单 主要为bat exe 等PE文件
		typeBlackList: {
			type: String,
			default: 'exe;bat;dll;com;sys;ocx'
		},
		limitSize: {
			// 单位Kb
			type: Number,
			default: 0
		},
		extendData: {
			type: Object,
			default: function() {
				return {}
			}
		},
		editable: {
			type: Boolean,
			default: true
		},
		previewMode: {
			type: Boolean,
			default: true
		},
		extendDesc: {
			type: String,
			default: ''
		},
		title: {
			type: String,
			default: '附件'
		},
		btnTitle: {
			type: String,
			default: '附件'
		},
		disabled: {
			type: Boolean,
			default: false
		},
		isDisplayDefaultElement: {
			default: true,
			type: Boolean
		}
	},
	computed: {
		imageList() {
			return this.fileList.filter(file => file.ex_type === 'image')
		},
		// 正在上传的文件列表，用于显示进度条
		uploadingFileList() {
			return this.uploadFileList.filter(file => !file.success)
		},
		disablePreview() {
			return function(type) {
				if (type === 'pdf' || type === 'image' || type === 'other') {
					return false
				} else {
					return true
				}
			}
		}
	},
	methods: {
		openUploadDialog() {
			if (!(this.previewMode && !this.editable)) {
				this.visible = true
			} else {
				this.previewVisible = true
			}
		},
		open() {
			this.postData = {
				sourceType: this.sourceType,
				sourceId: this.sourceId
			}
			this.viewerId = 'viewer' + this.sourceType + this.sourceId + Math.floor(Math.random() * 100)
			this.postData = { ...this.postData, ...this.extendData }
			this.loadData()
			this.listType = this.defaultListType
		},
		previewOpen() {
			this.$nextTick(_ => {
				this.$refs.preview.open()
			})
		},
		previewClose() {
			this.$nextTick(_ => {
				this.$refs.preview.close()
			})
		},
		loadData() {
			if (isNaN(this.sourceId)) {
				return
			}
			let data = {
				qry_sourceType: this.sourceType,
				qry_sourceId: this.sourceId
			}
			this.fileList = []
			getAction(this.url.query, { ...data, ...this.extendData }).then(res => {
				if (res.success) {
					res.result.forEach(file => {
						this.bindFileDisplayUrl(file)
					})
					setTimeout(() => {
						this.fileList = res.result
					}, 200)
				} else {
					this.$tap.alert(res.message, 'warning')
				}
			})
		},
		/** 格式化日期 YYYY-MM-dd HH:mm:ss */
		dateFormat(row, column, cellValue, index) {
			let dateValue = row[column.property]
			return this.$tap.date.parseTime(dateValue)
		},
		beforeUpload(file) {
			if (this.limitCount < this.fileList.length + 1 + this.waitCount) {
				this.$tap.alert(`最多只能上传${this.limitCount}个附件!`, 'warning')
				return false
			}
			if (this.limitType) {
				let fileType = this.getFileExt(file.name)
				let isRight = false
				for (let type of this.limitType.split(';')) {
					if (type.indexOf(fileType) > -1) {
						isRight = true
						break
					}
				}
				if (!isRight) {
					this.$tap.alert(`上传附件只能是 ${this.limitType}格式!`, 'warning')
					return false
				}
			}
			if (this.typeBlackList) {
				let fileType = this.getFileExt(file.name)
				let isRight = false
				for (let type of this.typeBlackList.split(';')) {
					if (type.indexOf(fileType) > -1) {
						isRight = true
						break
					}
				}
				if (isRight) {
					this.$tap.alert(`上传附件不允许为 ${this.typeBlackList}格式!`, 'warning')
					return false
				}
			}
			if (this.limitSize > 0) {
				if (file.size / 1024 > this.limitSize) {
					this.$tap.alert(`上传附件不能大于 ${this.limitSize}kb!`, 'warning')
					return false
				}
			}
			this.waitCount++
			return true
		},
		/** zhanglongfei 2020.9.18增加上传文件进度条，配套有compute中的uploadingFileList，data中uploadFileList,上传组件的file-list和class=upload-queue的div */
		progress(event, file, fileList) {
			this.uploadFileList = fileList
		},
		formatProcess(percentage) {
			return `${percentage}%`
		},
		uploadSuccess(response, file) {
			this.waitCount--
			let existFile = this.uploadFileList.find(m => m.uid === file.uid)
			if (existFile) {
				this.$set(existFile, 'success', true)
			}
			if (response.success) {
				this.$tap.message('上传成功')
				this.bindFileDisplayUrl(response.result)
				this.fileList.push(response.result)
			} else {
				this.$tap.alert(`上传失败：${response.message}`, 'warning')
			}
		},
		uploadFail() {
			this.waitCount--
		},
		bindFileDisplayUrl(file) {
			file.ex_typeUrl = other
			file.ex_type = 'other'
			file.ex_base64 = ''
			let fileType = ';' + this.getFileExt(file.displayname) + ';'
			for (let key in this.fileTypeIcon) {
				if (key.indexOf(fileType) > -1) {
					file.ex_typeUrl = this.fileTypeIcon[key]
					// 目前在线显示的文件，仅支持图片和pdf
					if (key.indexOf(';jpg;') > -1) {
						file.ex_type = 'image'
						// if (this.listType === 'thumb') this.display(file)
						this.display(file)
					} else if (key.indexOf(';pdf;') > -1) {
						file.ex_type = 'pdf'
					}
					break
				}
			}
		},
		display(file) {
			if (!file.id) return
			axios({
				url: this.url.download,
				method: 'post',
				data: { attachmentId: file.id },
				responseType: 'arraybuffer'
			}).then(response => {
				file.ex_base64 = 'data:image/png;base64,' + this.$tap.util.bufferToBase64(response)
			})
		},
		async asyncDisplay(file) {
			if (!file.id) return
			let res = await axios({
				url: this.url.download,
				method: 'post',
				data: { attachmentId: file.id },
				responseType: 'arraybuffer'
			})
			file.ex_base64 = 'data:image/png;base64,' + this.$tap.util.bufferToBase64(res)
		},
		getFileExt(fileName) {
			let arr = fileName.split('.')
			if (arr.length === 0) return ''
			else return arr[arr.length - 1].toString().toLowerCase()
		},
		handleView(file) {
			if (file.ex_type === 'image') {
				this.viewImage(file)
			} else {
				this.viewWord(file)
			}
		},
		viewWord(file) {
			const loading = this.$loading({
				lock: true,
				text: 'Loading',
				spinner: 'el-icon-loading',
				background: 'rgba(0, 0, 0, 0.7)'
			})
			axios({
				url: this.url.viewWord,
				method: 'post',
				data: { attachmentId: file.id },
				responseType: 'blob'
			})
				.then(response => {
					loading.close()
					let url = this.getObjectURL(response)
					this.pdfFile = `/static/plugins/pdfjs/web/viewer.html?file=${url}`
					this.pdfTitle = file.displayname
					this.pdfVisible = true
				})
				.catch(err => {
					loading.close()
					if (err && err.response && err.response.status === 417) {
						this.$tap.alert('暂不支持该格式文件查看', 'warning')
					}
				})
		},
		viewImage(file) {
			if (!this.imageViewer) {
				this.imageViewer = new Viewer(document.getElementById(this.viewerId), {
					url(image) {
						return image.ex_base64
					},
					title: [
						1,
						(image, imageData) => {
							return `${this.imageList[this.imageViewer.index].displayname} (${imageData.naturalWidth} × ${imageData.naturalHeight})`
						}
					]
				})
			}
			this.imageViewer.options.zIndex = 666666
			this.imageViewer.images = this.imageList
			this.imageViewer.length = this.imageViewer.images.length
			let idx = this.imageList.findIndex(item => item.id === file.id)
			this.imageViewer.index = idx
			console.log('this.imageViewer.show()', this.imageViewer.show())
		},
		viewPdf(file) {
			axios({
				url: this.url.download,
				method: 'post',
				data: { attachmentId: file.id },
				responseType: 'blob'
			}).then(response => {
				let url = this.getObjectURL(response)
				this.pdfFile = `/static/plugins/pdfjs/web/viewer.html?file=${url}`
				this.pdfTitle = file.displayname
				this.pdfVisible = true
			})
		},
		getObjectURL(file) {
			let url = null
			if (window.createObjectURL !== undefined) {
				// basic
				url = window.createObjectURL(file)
			} else if (window.webkitURL !== undefined) {
				// webkit or chrome
				try {
					url = window.webkitURL.createObjectURL(file)
				} catch (error) {}
			} else if (window.URL !== undefined) {
				// mozilla(firefox)
				try {
					url = window.URL.createObjectURL(file)
				} catch (error) {}
			}
			return url
		},
		handleRemove(file, fileList) {
			this.$tap.confirm('确定移除文件').then(() => {
				this.doRemove(file)
			})
		},
		doRemove(file) {
			deleteAction(this.url.delete, { ids: file.id }).then(res => {
				if (res.success) {
					this.$tap.message('删除成功')
					this.fileList.splice(this.fileList.findIndex(item => item.id === file.id), 1)
					this.fileCount = this.fileList.length
				} else {
					this.$tap.alert(`删除失败：${res.message}`, 'warning')
				}
			})
		},
		handleDownload(file) {
			axios({
				url: this.url.download,
				method: 'post',
				data: { attachmentId: file.id },
				responseType: 'blob'
			}).then(response => {
				this.doDownload(response, file)
			})
		},
		doDownload(response, file) {
			var blob = new Blob([response], { type: 'application/octet-stream;charset=utf-8' })
			var tempObjectUrl = window.URL.createObjectURL(blob)
			var aLink = document.createElement('a')
			aLink.style.display = 'none'
			aLink.download = file.displayname
			aLink.href = tempObjectUrl
			document.body.appendChild(aLink)
			aLink.click()
			document.body.removeChild(aLink)
			window.URL.revokeObjectURL(tempObjectUrl)
		},
		handleExceed(files, fileList) {
			this.$tap.alert(`最多可以上传${this.limitCount}个文件`, 'warning')
		},
		queryCount() {
			if (!this.sourceType || !this.sourceId) {
				this.fileList = []
				this.fileCount = 0
				return
			}
			this.postData = {
				sourceType: this.sourceType,
				sourceId: this.sourceId
			}
			getAction(this.url.queryCount, this.postData).then(res => {
				this.fileList = []
				this.fileCount = res.result
			})
		},
		close() {
			this.waitCount = 0
			this.uploadFileList = []
			this.$emit('close', this.fileList)
		}
	},
	mounted() {
		this.queryCount()
	},
	created() {},
	watch: {
		sourceType(newVal, oldVal) {
			this.queryCount()
		},
		sourceId(newVal, oldVal) {
			this.queryCount()
		}
	}
}
</script>

<style lang="scss">
.exchange-tab .el-radio-button span.el-radio-button__inner {
	padding-right: 10px;
	padding-left: 10px;
}
</style>
<style scoped lang="scss">
.tl-upload {
	position: relative;
}
.upload-queue {
	clear: both;
	position: absolute;
	width: 80%;
	background: white;
	text-align: left;
	z-index: 2;
	left: 125px;
	top: 0;
	.el-progress {
		display: inline-block;
		margin: 6px 10px 0 0;
		width: 150px;
	}
}
</style>
